home *** CD-ROM | disk | FTP | other *** search
- # Should rename this to alphaIndices.tcl or something like that.
-
- # Clean up temporary files:
- proc removeTemporaryFiles {} {
- global PREFS
- if {[file exists [file join $PREFS tmp]]} {
- foreach f [glob -dir [file join $PREFS tmp] -nocomplain *] {
- message "removing [file tail $f]…"
- file delete $f
- }
- }
- message "all temporary files removed"
- }
-
- set alpha::rebuilding 0
-
- proc alpha::rebuildPackageIndices {} {
- alpha::makeIndices
- message "Indices and package menu rebuilt."
- }
-
- proc alpha::makeIndices {} {
- # add all new directories to the auto_path
- alpha::makeAutoPath
- # ensure count is correctly set - otherwise we'd probably have to
- # rebuild next time we started up.
- alpha::rectifyPackageCount
- set types {index::feature index::mode index::uninstall index::preinit index::maintainer index::description index::help index::disable index::flags}
- global pkg_file HOME alpha::rebuilding alpha::version \
- index::oldmode alpha::tclversion
- eval global $types
- # Remember those packages which have already had their 'one-time init' called.
- foreach pkg [array names index::feature] {
- if {[llength [set index::feature($pkg)]] > 3} {
- if {![string length [lindex [set index::feature($pkg)] 3]]} {
- # It was activated at some point, or has < 4 elements.
- lappend already_activated $pkg
- }
- }
- }
- # Remember the old feature array, so we can re-instantiate mode-menus
- # which otherwise disappear from the array.
- array set feature_temp [array get index::feature]
- # store old mode information so we can check what changed
- catch {cache::readContents index::mode}
- catch {array set index::oldmode [array get index::mode]}
-
- catch {eval cache::delete $types}
- foreach type $types {
- catch {unset $type}
- }
- foreach dir [list SystemCode Modes Menus Packages] {
- lappend dirs [file join ${HOME} Tcl ${dir}]
- eval lappend dirs [glob -types d -dir [file join ${HOME} Tcl ${dir}] -nocomplain *]
- }
- if {[file exists [file join ${HOME} AlphaCore]]} {
- lappend dirs [file join ${HOME} AlphaCore]
- }
- set alpha::rebuilding 1
-
- # provide the 'Alpha' and 'AlphaTcl' packages
- ;alpha::extension Alpha ${alpha::version} {} help {file "Alpha Manual"}
- ;alpha::extension AlphaTcl ${alpha::tclversion} {} help {file "Extending Alpha"}
- # declare 2 different scan contexts:
- set cid_scan [scancontext create]
- scanmatch $cid_scan "^\[ \t\]*alpha::(declare|menu|mode|flag|extension|feature|package\[ \t\]+(uninstall|disable|maintainer|help))\[ \t\\\\\]" {
- incr rebuild_cmd_count 1
- }
- scanmatch $cid_scan "^\[ \t\]*newPref\[ \t\]" {
- if {[incr numprefs] == 1} {
- set newpref_start $matchInfo(offset)
- }
- }
- set cid_help [scancontext create]
- scanmatch $cid_help "^\[ \t\]*#" {
- if {[expr {$linenum +1}] != $matchInfo(linenum)} { set hhelp "" }
- append hhelp [string trimleft $matchInfo(line) " \t#"] " "
- set linenum $matchInfo(linenum)
- }
-
- scanmatch $cid_help "^\[ \t\]*newPref\[ \t\]" {
- if {[expr {$linenum +1}] == $matchInfo(linenum)} {
- if {$hhelp != ""} {
- set got $matchInfo(line)
- # While the line either ends in a continuation backslash,
- # or has an unmatched brace:
- while {![info complete "${got}\n"]} {
- append got [gets $matchInfo(handle)]
- if {[eof $matchInfo(handle)]} {break}
- }
- # Tcl really ought to supply us with a built-in 'parseWords'
- if {[catch {parseWords $got} res]} {
- if {[askyesno "Had a problem extracting preferences help information\
- from '$got'. View error?"] == "yes"} {
- alertnote [string range $res 0 240]
- error "problem"
- }
- }
- set pkg [lindex $res 4]
- set var [lindex $res 2]
- # allow comment to over-ride the mode/package
- regexp "^\\((\\w+)\\)\[ \t\]*(.*)\$" $hhelp "" pkg hhelp
- if {$pkg == "" || $pkg == "global"} {
- set prefshelp($var) $hhelp
- } else {
- set prefshelp($pkg,$var) $hhelp
- }
- }
- }
- set hhelp ""
- if {[incr numprefs -1] == 0} {
- error "done"
- }
- }
-
- global rebuild_cmd_count
- foreach d $dirs {
- foreach f [glob -nocomplain -dir $d *.tcl] {
- if {![catch {alphaOpen $f} fid]} {
- message "scanning [file tail $f]…"
- set numprefs 0
- set rebuild_cmd_count 0
- # check for 'newPref' or 'alpha::package' statements
- scanfile $cid_scan $fid
- if {$numprefs > 0} {
- message "scanning [file tail $f]…($numprefs prefs)"
- incr newpref_start -520
- seek $fid [expr {$newpref_start > 0 ? $newpref_start : 0}]
- set linenum -2
- set hhelp ""
- if {[catch [list scanfile $cid_help $fid] err]} {
- if {$err != "done"} {
- if {[askyesno "Had a problem extracting preferences help information\
- from '[file tail $f]'. View error?"] == "yes"} {
- alertnote [string range $err 0 240]
- }
- }
- }
- }
- close $fid
- if {$rebuild_cmd_count > 0} {
- message "scanning [file tail $f] for packages"
- set pkg_file $f
- if {[catch {uplevel \#0 [list source $f]} res] != 11} {
- if {[askyesno "Had a problem extracting package information from [file tail $f]. View error?"] == "yes"} {
- alertnote [string range $res 0 240]
- }
- }
- }
- }
- }
- }
- catch {unset rebuild_cmd_count}
- set alpha::rebuilding 0
-
- scancontext delete $cid_scan
- scancontext delete $cid_help
- cache::create index::prefshelp variable prefshelp
-
- foreach type $types {
- cache::add $type "variable" $type
- if {($type != "index::feature") && ($type != "index::flags")} { catch {unset $type} }
- }
- catch {unset index::oldmode}
- catch {unset pkg_file}
- #foreach n [array names index::feature] {}
- global alpha::requirements
- if {[info exists alpha::requirements]} {
- foreach itm ${alpha::requirements} {
- set m [lindex $itm 0]
- set req [lindex $itm 1]
- if {[catch {package::versionCheck [lindex $req 0] [lindex $req 2]} err]} {
- alertnote "$m mode requirements failure: $err You should upgrade that package."
- }
- }
- }
-
- # Re-initialise those features which were created on the fly.
- # If we completely deleted some packages, their information will be recreated here,
- # until the next time you quit Alpha.
- foreach pkg [array names feature_temp] {
- if {![info exists index::feature($pkg)]} {
- set index::feature($pkg) $feature_temp($pkg)
- }
- }
-
- # Clear the 'one-time init' script for those packages which already had it cleared.
- if {[info exists already_activated]} {
- foreach pkg $already_activated {
- if {[info exists index::feature($pkg)]} {
- if {[llength [set index::feature($pkg)]] > 3} {
- set index::feature($pkg) [lreplace [set index::feature($pkg)] 3 3 ""]
- }
- }
- }
- }
-
- message "Package index rebuilt."
- }
-
- proc alpha::reportError {string} {
- global reportErrors errorInfo
- if {$reportErrors} {
- set errorCache $errorInfo
- if {[dialog::yesno -y "View the error" -n "Continue" \
- $string]} {
- dialog::alert $errorCache
- }
- } else {
- global alpha::errorLog
- append alpha::errorLog $string
- }
- }
-
- proc userMessage {{alerts 1} {message ""}} {
- if {$alerts} {
- alertnote $message
- } else {
- message $message
- }
- }
-
- namespace eval flag {}
-
- # Always use this proc, don't mess with 'flag::types' directly.
- proc flag::addType {type} {
- global flag::types
- if {[lsearch -exact ${flag::types} $type] == -1} {
- lappend flag::types $type
- }
- }
-
- # Declare basic preference types
- namespace eval flag {}
- set flag::types [list "flag" "variable" "binding" "menubinding" \
- "file" "io-file" "funnyChars" "url"]
- # Note: other types are triggered by vars ending in 'Colour', 'Color',
- # 'Folder', 'Path', 'Mode', 'Sig', or 'SearchPath'
-
- namespace eval global {}
-
- ##
- # -------------------------------------------------------------------------
- #
- # "newPref" --
- #
- # Define a new preference variable/flag. You can call this procedure
- # either with multiple arguments or with a single list of all the
- # arguments. So 'newPref flag Hey ...' or 'newPref {flag Hey ...}'
- # are both fine.
- #
- # 'type' is one of:
- # 'flag' (on/off only), 'variable' (anything), 'binding' (key-combo)
- # 'menubinding' (key-combo which works in a menu), 'file' (input only),
- # 'io-file' (either input or output). Variables whose name ends in
- # Sig, Folder, Path, Mode, Colour, Color or SearchPath (case matters here)
- # are treated differently, but are still considered of type 'variable'.
- # For convenience this proc will map types sig, folder, color, ...
- # into 'variable' for you, _if_ the variable ends with the correct
- # string.
- #
- # 'name' is the var name,
- #
- # 'val' is its default value (which will be ignored if the variable
- # already has a value)
- #
- # 'pkg' is either 'global' to mean a global preference, or the name
- # of the mode or package (no spaces) for which this is a preference.
- #
- # 'pname' is a procedure to call if this preference is changed by
- # the user (no need to setup a trace). This proc is only called
- # for changes made through prefs dialogs or prefs menus created by
- # Alpha's core procs. Other changes are not traced.
- #
- # Depending on the previous values, there are two optional arguments
- # with the following uses:
- #
- # TYPE:
- #
- # variable:
- #
- # 'options' is a list of items from which this preference takes a single
- # item.
- # 'subopt' is any of 'item', 'index', 'varitem' or 'varindex' or 'array', where
- # 'item' indicates the pref is simply an item from the given list
- # of items, 'index' indicates it is an index into that list, and
- # 'var*' indicates 'items' is in fact the name of a global variable
- # which contains the list. 'array' means take one of the values from an array.
- # If no value is given, 'item' is the default
- #
- # binding:
- #
- # 'options' is the name of a proc to which this item should be bound.
- # If options = '1', then we Bind to the proc with the same name as
- # this variable. Otherwise we do not perform automatic bindings.
- #
- # 'subopt' indicates whether the binding is mode-specific or global.
- # It should either be 'global' or the name of a mode. If not given,
- # it defaults to 'global' for all non-modes, and to mode-specific for
- # all packages. (Alpha tests if something is a mode by 'mode::exists')
- # -------------------------------------------------------------------------
- ##
- proc newPref {vtype {name {}} {val 0} {pkg "global"} {pname ""} {options ""} {subopt ""}} {
- if {$name == {}} { uplevel 1 newPref $vtype}
-
- global allFlags allVars tclvars modeVars flag::procs \
- flag::type flag::types alpha::earlyPrefs
- # 'link' means link this variable with Alpha's internals.
- if {[regexp {^early(.*)$} $vtype "" vtype]} {
- lappend alpha::earlyPrefs $name
- }
- if {[regexp {^link(.*)$} $vtype "" vtype]} {
- linkVar $name
- # linked variables over-ride differently to normal preferences.
- if {$val != ""} { global $name ; set $name $val }
- }
- set bad 1
- foreach ty ${flag::types} {
- if {[string first $vtype $ty] == 0} {
- set vtype $ty
- set bad 0
- break
- }
- }
- if {$bad} {
- foreach ty {SearchPath Folder Path Mode Colour Color Sig} {
- if {[string first $vtype [string tolower $ty]] == 0} {
- if {[regexp -- "${ty}\$" $name]} {
- set vtype variable
- set bad 0
- break
- } else {
- error "Type '$vtype' requires the variable's name to end in '$ty'"
- }
- }
- }
- if {$bad} {error "Unknown type '$vtype' in call to newPref"}
- }
- if {$pkg == "global"} {
- switch -- $vtype {
- "flag" {
- lappend allFlags $name
- }
- "variable" {
- lappend allVars $name
- }
- default {
- set flag::type($name) $vtype
- lappend allVars $name
- }
- }
-
- global $name mode global::_varMem
- if {![info exists tclvars] || ([lsearch -exact $tclvars $name] == -1)} {lappend tclvars $name}
- if {[info exists mode] && $mode != ""} {
- global ${mode}modeVars
- if {[info exists $name] && [info exists ${mode}modeVars($name)]} {
- # Don't override an existing mode variable which has been
- # copied into the global namespace; instead just place
- # value in the global cache
- set global::_varMem($name) $val
- } else {
- if {![info exists $name]} {set $name $val} else { set val [set $name] }
- }
- } else {
- if {![info exists $name]} {set $name $val} else { set val [set $name] }
- }
- } else {
- global ${pkg}modeVars mode alpha::changingMode
- if {![info exists modeVars] || ([lsearch -exact $modeVars $name] == -1)} {lappend modeVars $name}
-
- if {![info exists ${pkg}modeVars($name)]} {
- set ${pkg}modeVars($name) $val
- } else {
- set val [set ${pkg}modeVars($name)]
- }
- if {!${alpha::changingMode} && ($mode == $pkg)} {
- global $name global::_varMem
- # Need to load up this global cache for when mode changes!
- if {[info exists $name]} {
- set global::_varMem($name) [set $name]
- }
- set $name $val
- }
- switch -- $vtype {
- "flag" {
- if {[lsearch -exact $allFlags $name] == -1} {
- lappend allFlags $name
- }
- }
- "variable" {
- lappend allVars $name
- }
- default {
- set flag::type($name) $vtype
- lappend allVars $name
- }
- }
- }
- # handle 'options'
- if {$options != ""} {
- switch -- $vtype {
- "variable" {
- global flag::list
- if {$subopt == ""} { set subopt "item" }
- if {[lsearch -exact "array item index varitem varindex" $subopt] == -1} {
- error "Unknown list element type '$subopt' in call to newPref."
- }
- set flag::list($name) [list $subopt $options]
- }
- "binding" {
- global flag::binding
- if {[mode::exists $pkg]} {
- if {$subopt == ""} {
- set subopt $pkg
- } else {
- if {$subopt == "global"} { set subopt "" }
- }
- }
- set flag::binding($name) [list $subopt $options]
- if {$options == 1} { set options $name }
- catch "Bind [keys::toBind $val] [list $options] $subopt"
- }
- }
- }
- # register the 'modify' proc
- if {[string length $pname]} {
- set flag::procs($name) $pname
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "alpha::rectifyPackageCount" --
- #
- # Returns 1 if count has changed. Note that we don't check for a
- # changed count in 'SystemCode', since users won't install stuff there.
- # -------------------------------------------------------------------------
- ##
- proc alpha::rectifyPackageCount {} {
- global HOME file::separator
- # check things haven't changed
- foreach d {Modes Menus Packages} {
- lappend count [llength [glob -nocomplain -dir [file join ${HOME} Tcl ${d}] "*.tcl"]] \
- [llength [glob -nocomplain -dir [file join ${HOME} Tcl ${d}] -types d *]]
- }
- if {![cache::exists index::count[join $count -]]} {
- cache::deletePat index::count*
- cache::create index::count[join $count -]
- return 1
- } else {
- return 0
- }
- }
-
- proc alpha::checkConfiguration {} {
- global alpha::version alpha::tclversion
- if {![cache::exists index::feature] || (![cache::exists index::mode]) \
- || ([alpha::package versions Alpha] != ${alpha::version}) \
- || ([alpha::package versions AlphaTcl] != ${alpha::tclversion})} {
- set rebuild 1
- # We no longer zap the cache
- if {0} {
- # If there's no package information stored at all, or if Alpha's
- # version number has changed, zap the cache. This may not be
- # required, but is safer since core-code changes may modify the
- # form of the cache, or change the format of cached menus etc.
- global PREFS
- if {[cache::exists configuration]} {
- # in case we crashed or some other weirdness
- catch {file delete [file join ${PREFS} configuration]}
- # now backup the configuration file
- # Alpha has a bad filesystem bug which can sometimes arise
- # here, so we do this crazy stuff.
- if {[catch {file rename [file join ${PREFS} Cache configuration] \
- [file join ${PREFS} configuration]}]} {
- dialog::alert "You've hit an unfortunate filesystem bug in Alpha.\
- Unfortunately there is no workaround. Alpha will now forget\
- your globally active features, and some other preferences.\r\
- Sorry! This will be fixed in Alpha 8.0."
- }
- rm -r [file join ${PREFS} Cache]
- file mkdir [file join ${PREFS} Cache]
- catch {file rename [file join ${PREFS} configuration] \
- [file join ${PREFS} Cache configuration]}
- } else {
- rm -r [file join ${PREFS} Cache]
- file mkdir [file join ${PREFS} Cache]
- }
- }
- } else {
- set rebuild [alpha::rectifyPackageCount]
- }
- return $rebuild
- }
-
-
-